package com.liujun.io.nio.trans.tran;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Semaphore;

import com.liujun.io.nio.trans.util.IOutils;
import com.liujun.io.nio.trans.util.PropertiesUtils;

/**
 * 前端的数据向后端传输通道
* 源文件名：TransProxyFile.java
* 文件版本：1.0.0
* 创建作者：liujun
* 创建日期：2016年8月24日
* 修改作者：liujun
* 修改日期：2016年8月24日
* 文件描述：liujun
* 版权所有：Copyright 2016 zjhz, Inc. All Rights Reserved.
*/
public class TransProxyByteMap implements TransProxyInf {

    /**
     * 生成文件的路径信息
     * 
     * @字段说明 url
     */
    private String url;

    /**
     * 文件信息
     */
    private File fileInfo;

    /**
     * 文件大小,64K
     */
    private static final int FILE_SIZE = 1024 * 1;

    /**
     * 随机文件读取流程
     * 
     * @字段说明 randomFile
     */
    private RandomAccessFile randomFile = null;

    /**
     * 许可信号量
     */
    private Semaphore semp = new Semaphore(1);

    /**
     * 通道信息
     * 
     * @字段说明 channel
     */
    private FileChannel channel = null;

    /**
     * 内存影射区域
    * @字段说明 mapBuffer
    */
    private MappedByteBuffer mapBuffer;

    /**
     * 文件时间
     * 
     * @字段说明 fileTime
     */
    private long fileTime;

    public TransProxyByteMap() {
        this.openFile();
    }

    /**
     * 将网络通道转换为file 方法描述
     * 
     * @param socketChanel
     * @创建日期 2016年8月11日
     */
    public boolean tranFrom(SocketChannel socketChanel) throws IOException {
        if (channel.isOpen()) {
            boolean accquicr = false;
            try {
                // 试图去拿到许可执行
                accquicr = semp.tryAcquire();

                if (accquicr) {

                    if (socketChanel.isOpen()) {

                        if (mapBuffer.hasRemaining()) {

                            socketChanel.write(new ByteBuffer[] { mapBuffer }, 0, FILE_SIZE);

                            int size = socketChanel.write(mapBuffer);

                            if (size > 0) {
                                // 强制写入
                                System.out.println("读入数据:" + size + ",信息:" + mapBuffer.position());

                            }
                        }

                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
                throw e;
            } finally {
                if (accquicr) {
                    // 释放许可
                    semp.release();
                }
            }
        }
        return false;
    }

    /**
     * 将数据写入后端通道信息 方法描述
     * 
     * @param toChannel
     * @创建日期 2016年8月11日
     */
    public boolean tranTo(SocketChannel toChannel) throws IOException {
        if (channel.isOpen()) {
            boolean accquicr = false;
            try {
                // 试图去拿到许可执行
                accquicr = semp.tryAcquire();
                if (accquicr) {

                    if (toChannel.isOpen()) {

                        if (mapBuffer.hasRemaining()) {
                            byte[] b = new byte[1024];
                            while (mapBuffer.get(b).position() < mapBuffer.limit()) {
                                int size = toChannel.write(mapBuffer);
                                System.out.println("写入目标:" + size);
                            }
                        }

                        // channel.position(0);
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
                throw e;
            } finally {
                if (accquicr) {
                    semp.release();
                }

            }
        }

        return true;

    }

    /**
     * 进行文件流通道的打开操作 方法描述
     * 
     * @创建日期 2016年8月15日
     */
    public void openFile() {
        try {
            // 系统时间纳秒数，以保证文件不重复
            fileTime = System.nanoTime();
            url = PropertiesUtils.getInstance().getValue("classPath") + "/" + fileTime;
            fileInfo = new File(url);
            randomFile = new RandomAccessFile(fileInfo.getAbsolutePath(), "rw");

            channel = randomFile.getChannel();

            mapBuffer = channel.map(MapMode.READ_WRITE, 0, FILE_SIZE);

            mapBuffer.position(0);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 重置连接信息 方法描述
     * 
     * @创建日期 2016年8月19日
     */
    public void reset() {
    }

    /**
     * 关闭流信息 方法描述
     * 
     * @创建日期 2016年8月13日
     */
    public void close() {

        IOutils.closeStream(channel);
        IOutils.closeStream(randomFile);
    }

}
